package com.bluexmicro.ota2.ui.screen.facecustom

import android.bluetooth.le.ScanResult
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.ImageDecoder
import android.graphics.Paint
import android.net.Uri
import android.os.Build
import android.provider.MediaStore
import android.util.Log
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.bluexmicro.ota.FirmwareHelper
import com.bluexmicro.ota.asset.AssetProcess
import com.bluexmicro.ota.customface.CustomFaceModel
import com.bluexmicro.ota.customface.TextOffset
import com.bluexmicro.ota2.ui.screen.dfu.TimeConsuming
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.launch
import java.io.File


class CustomFaceViewModel : ViewModel() {

    val template = mutableStateOf<CustomFaceModel?>(null)
    val textOffset = mutableStateOf<TextOffset?>(null)
    val target = mutableStateOf<ScanResult?>(null)
    val progress = mutableStateOf(-1f)
    val image = mutableStateOf<Bitmap?>(null)

    val updating = derivedStateOf {
        progress.value >= 0f
    }

    val canUpdate = derivedStateOf {
        template.value != null && target.value != null && updating.value.not()
    }

    //失败
    val error = mutableStateOf<String?>(null)

    //成功
    val timeConsuming = mutableStateOf<TimeConsuming?>(null)

    fun unzipTemplate(context: Context, file: File) = viewModelScope.launch(Dispatchers.IO) {
        template.value = try {
            FirmwareHelper.unzipCustomFaceTemplate(context, file)
        } catch (e: Exception) {
            e.printStackTrace()
            null
        }

        textOffset.value = null
        image.value = null
    }

    fun setTarget(scanResult: ScanResult?) {
        if (scanResult != null)
            target.value = scanResult
    }

    fun onPictureSelected(context: Context, uri: Uri?) = viewModelScope.launch(Dispatchers.IO) {
        if (uri != null) {

            val bm = try {
                if (Build.VERSION.SDK_INT < 28) {
                    MediaStore.Images.Media.getBitmap(context.contentResolver, uri)
                } else {
                    val source = ImageDecoder.createSource(context.contentResolver, uri)
                    ImageDecoder.decodeBitmap(
                        source
                    ) { decoder, _, _ ->
                        decoder.allocator = ImageDecoder.ALLOCATOR_SOFTWARE
                        decoder.isMutableRequired = true
                    }
                }
            } catch (e: Exception) {
                error.value = "无效图片"
                null
            } ?: return@launch

            template.value?.run {
                val tmp = Bitmap.createScaledBitmap(bm, screenWidth * 2, screenHeight * 2, true)
                Bitmap.createScaledBitmap(tmp, screenWidth, screenHeight, true)
            }?.apply {
                image.value = this
            }
        }
    }


    fun startUpdate(context: Context) = viewModelScope.launch(Dispatchers.Default) {
        var setupTimeConsuming = 0L
        val updateTimeConsuming: Long
        val bitmap = image.value!!
        val tmp = template.value ?: return@launch

        Log.e("TAG", "width: ${bitmap.width}")
        Log.e("TAG", "height: ${bitmap.height}")


        val model = try {
            tmp.createAsset(bitmap, textOffset.value)
        } catch (e: Exception) {
            error.value = e.message
            null
        } ?: return@launch

        val assetProcess = AssetProcess()
        val process = try {
            progress.value = 0f
            val anchor1 = System.currentTimeMillis()
            assetProcess.initialize(context, target.value!!.device).apply {
                setupTimeConsuming = System.currentTimeMillis() - anchor1
            }
        } catch (e: Exception) {
            error.value = e.message
            null
        } ?: return@launch
        val anchor2 = System.currentTimeMillis()
        process.update(model)
            .catch {
                error.value = it.message
                progress.value = -1f
            }.collect {
                progress.value = it
            }
        updateTimeConsuming = System.currentTimeMillis() - anchor2
        timeConsuming.value = TimeConsuming(setupTimeConsuming, updateTimeConsuming)
        delay(500)
        progress.value = -1f
        process.release()
    }


}